/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/*!
\file			ETI_CplxTxt.cc
\date			september 2011
\author		TNick

\brief		Contains the implementation for ETI_CplxTxt class


Copyright (c) 2011, Nicu Tofan
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL NICU TOFAN BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
//
//
//
//
/*  INCLUDES    ------------------------------------------------------------ */

#include	<main.h>

#include	<QDebug>
#include	<QRect>
#include	<QStyleOptionGraphicsItem>
#include	<QGraphicsScene>
#include	<QGraphicsSceneMouseEvent>
#include	<QEvent>
#include	<QKeyEvent>
#include	<QApplication>
#include	<QInputContext>
#include	<QPainter>

#include	<sheet/ETSheet.h>
#include	<sheet/ETSheetView.h>
#include	<sheet/ETSubItem.h>

#include	<sheet/subitems/ETSI_Fract.h>
#include	<sheet/subitems/ETSI_HText.h>
#include	<sheet/subitems/ETSI_Integ.h>
#include	<sheet/subitems/ETSI_Lim.h>
#include	<sheet/subitems/ETSI_LogicAc.h>
#include	<sheet/subitems/ETSI_Matrix.h>
#include	<sheet/subitems/ETSI_Radic.h>
#include	<sheet/subitems/ETSI_SText.h>
#include	<sheet/subitems/ETSI_Sum.h>



#include	<sheet/vp_cmd/ETVpCmd_EditSubI.h>

#include	"ETI_CplxTxt.h"

/*  INCLUDES    ============================================================ */
//
//
//
//
/*  CLASS    --------------------------------------------------------------- */
DDHC_CONTENT(ETI_CplxTxt)


/* ------------------------------------------------------------------------- */
void			ETI_CplxTxt::init		( void )
{
	setFlags(ItemIsMovable | ItemIsSelectable | ItemIsFocusable);

	/* initialise the embedded root item */
	it_r.setFather(this);
#ifdef APP_DEBUG
	it_r.setColor(QColor(Qt::white));
	it_r.setPen(qRgb(100,200,0));
#else
	it_r.setColor(QColor(Qt::white));
	it_r.setPen(0); /* black */
#endif

	DDHC_CONSTRUCT;

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
ETI_CplxTxt::ETI_CplxTxt	()
	: QGraphicsItem (NULL)
{

	init();

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
ETI_CplxTxt::ETI_CplxTxt	(
		ETSheet * sht, qreal loc_x, qreal loc_y)
	: QGraphicsItem (NULL)
{

	init();

	/* create a new, simple text */
	setPos(loc_x, loc_y);
	ETSI_SText * only_it;
#ifdef APP_DEBUG
	for (int i = 0; i < 1; i++)
	{
		only_it = new ETSI_SText();
		it_r.append(only_it);
	}
	only_it->setColor(Qt::red);
	only_it->setPen(qRgb(255,255,255));

	ETSI_Fract * fract_1 = new ETSI_Fract();
	it_r.append(fract_1);
	//ETSI_HText * htx_1 = new ETSI_HText();
	//it_r.append(htx_1);
	ETSI_Integ * intg_1 = new ETSI_Integ();
	it_r.append(intg_1);
	ETSI_Lim * lim_1 = new ETSI_Lim();
	it_r.append(lim_1);
	ETSI_LogicAc * la_1 = new ETSI_LogicAc();
	it_r.append(la_1);
	ETSI_Matrix * matr_1 = new ETSI_Matrix();
	it_r.append(matr_1);
	ETSI_Radic * radic_1 = new ETSI_Radic();
	it_r.append(radic_1);
	ETSI_SText * stx_1 = new ETSI_SText();
	it_r.append(stx_1);
	ETSI_Sum * sum_1 = new ETSI_Sum();
	it_r.append(sum_1);
	ETSI_Rows * rows_1 = new ETSI_Rows();
	it_r.append(rows_1);


#else
	only_it = new ETSI_SText();
	it_r.append(only_it);
	/* inherits the colors from it's father */
#endif


	recompute(true);

	sht->addItem(this);
	DDHC_REPARENT(sht);

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
ETI_CplxTxt::~ETI_CplxTxt	( void )
{
	DDHC_DESTRUCT

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QRectF			ETI_CplxTxt::boundingRect	( void ) const
{
	qreal adj_f = it_r.boundingBox().height() * 5 / 100;
	return it_r.boundingBox().adjusted(-adj_f, -adj_f, adj_f, adj_f);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void			ETI_CplxTxt::paint                  (
		QPainter *painter, const QStyleOptionGraphicsItem *option,
		QWidget *widget)
{
	Q_UNUSED(option);
	Q_UNUSED(widget);
	Q_UNUSED(painter);

	ETSheetView * vp = static_cast<ETSheetView *>(widget->parent());
	painter->setPen(QPen(option->palette.windowText(), 0, Qt::SolidLine));

	it_r.paint(vp, painter, QPointF(0, 0));
	if (option->state & (
				QStyle::State_Selected | QStyle::State_HasFocus))
	{
		QRectF adj = it_r.boundingBox();
		qreal adj_f = it_r.boundingBox().height() * 5 / 100;
		adj.adjust(-adj_f,-adj_f,adj_f,adj_f);
		painter->setPen(QPen(option->palette.windowText(), 0, Qt::DashLine));
		painter->setBrush(Qt::NoBrush);
		painter->drawRect(adj);
	}


}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QPainterPath	ETI_CplxTxt::shape() const
{
	QPainterPath path;
	path.addRect(boundingRect());
	return path;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool			ETI_CplxTxt::contains		(const QPointF &point) const
{
	return boundingRect().contains(point);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
bool			ETI_CplxTxt::sceneEvent		(QEvent * event)
{
	QEvent::Type t = event->type();
	if (t == QEvent::KeyPress || t == QEvent::KeyRelease)
	{
		int k = ((QKeyEvent *)event)->key();
		//        if (k == Qt::Key_Tab || k == Qt::Key_Backtab) {
		//            dd->sendControlEvent(event);
		//            return true;
		//        }
		Q_UNUSED(k);
	}
	bool result = QGraphicsItem::sceneEvent(event);

	// Ensure input context is updated.
	switch (event->type()) {
	case QEvent::ContextMenu:
	case QEvent::FocusIn:
	case QEvent::FocusOut:
	case QEvent::GraphicsSceneDragEnter:
	case QEvent::GraphicsSceneDragLeave:
	case QEvent::GraphicsSceneDragMove:
	case QEvent::GraphicsSceneDrop:
	case QEvent::GraphicsSceneHoverEnter:
	case QEvent::GraphicsSceneHoverLeave:
	case QEvent::GraphicsSceneHoverMove:
	case QEvent::GraphicsSceneMouseDoubleClick:
	case QEvent::GraphicsSceneMousePress:
	case QEvent::GraphicsSceneMouseMove:
	case QEvent::GraphicsSceneMouseRelease:
	case QEvent::KeyPress:
	case QEvent::KeyRelease:
		// Reset the focus widget's input context, regardless
		// of how this item gained or lost focus.
		if (QWidget *fw = qApp->focusWidget()) {
#ifndef QT_NO_IM
			if (QInputContext *qic = fw->inputContext()) {
				if (event->type() == QEvent::FocusIn ||
						event->type() == QEvent::FocusOut)
					qic->reset();
				else
					qic->update();
			}
#endif //QT_NO_IM
		}
		break;
		//	case QEvent::ShortcutOverride:
		//		dd->sendControlEvent(event);
		//		return true;
	default:
		break;
	}

	return result;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				ETI_CplxTxt::recompute		(bool b_full)
{
	it_r.recompute(b_full);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				ETI_CplxTxt::hitTest		(ETSubItem::HtData * h_data)
{
	if (it_r.boundingBox().contains(h_data->ck_pt))
	{
		it_r.hitTest(h_data);
	}
	else
		h_data->it_hitted = NULL;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				ETI_CplxTxt::mouseDoubleClickEvent (
		QGraphicsSceneMouseEvent * event )
{

	ETSheetView * p_vp = static_cast<ETSheetView *>(event->widget()->parent());
	ETSubItem::HtData h_data(event->pos());
	hitTest(&h_data);
	if (h_data.it_hitted != NULL)
	{

		//		QPoint mapped_tl = p_vp->mapFromScene(
		//					h_data.rct_bbx.x(),
		//					h_data.rct_bbx.y());
		//		QPoint mapped_br = p_vp->mapFromScene(
		//					h_data.rct_bbx.x(),
		//					h_data.rct_bbx.y());



		if (h_data.it_hitted->type() == ETSubItem::TYSTEXT)
		{
			ETVpCmd_EditSubI * sic = new ETVpCmd_EditSubI();
			sic->setSubItemToEdit(
						this,
						static_cast<ETSI_SText *>
						(h_data.it_hitted));
			p_vp->startCommand(sic);
		}



	}
	event->accept();
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				ETI_CplxTxt::performClick	(ETSheetView * p_vp, QPointF pt)
{
	ETSubItem::HtData h_data(pt);
	hitTest(&h_data);
	if (h_data.it_hitted != NULL)
	{
		if (h_data.ck_pt.x() - h_data.rct_bbx.x() > h_data.rct_bbx.width() / 2 )
		{
			p_vp->setSelRight();
		}
		else
		{
			p_vp->setSelLeft();
		}
		p_vp->setCurrentSubI(this, h_data.it_hitted);
		update();
	}

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				ETI_CplxTxt::mousePressEvent		(
		QGraphicsSceneMouseEvent *event)
{
	performClick(
				static_cast<ETSheetView *>(event->widget()->parent()),
				event->pos()
				);

	QGraphicsItem::mousePressEvent(event);

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				ETI_CplxTxt::mouseMoveEvent			(
		QGraphicsSceneMouseEvent *event)
{

	//	ETSubItem::HtData h_data(event->pos());
	//	hitTest(&h_data);
	//	if (h_data.it_hitted != NULL)
	//		{

	//			/// @todo do sth with resulted item
	//		}

	//	event->accept();
	QGraphicsItem::mouseMoveEvent(event);

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				ETI_CplxTxt::mouseReleaseEvent		(
		QGraphicsSceneMouseEvent *event)
{

	//	ETSubItem::HtData h_data(event->pos());
	//	hitTest(&h_data);
	//	if (h_data.it_hitted != NULL)
	//		{

	//			/// @todo do sth with resulted item
	//		}
	QGraphicsItem::mouseReleaseEvent(event);


}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void				ETI_CplxTxt::contextMenuEvent		(
		QGraphicsSceneContextMenuEvent *event)
{

	ETSubItem::HtData h_data(event->pos());
	hitTest(&h_data);
	if (h_data.it_hitted != NULL)
	{

		/// @todo do sth with resulted item
	}

	//QGraphicsItem::contextMenuEvent(event);
	event->accept();
}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
void				ETI_CplxTxt::reinit				( bool b_recomp )
{
	/// @todo replace the delete with a proper undo method
	LIST_BUG this << " root : ";
	it_r.dumpDbg2();

	it_r.erase();
	LIST_BUG this << " root : ";
	it_r.dumpDbg2();

	ETSI_SText * only_it = new ETSI_SText();
	it_r.append(only_it);
	it_r.setSizeDirty(NULL);
	LIST_BUG only_it << " appended: " ;
	LIST_BUG this << " after append root : ";
	it_r.dumpDbg2();

	if (b_recomp)
	{
		recompute(true);
	}

	LIST_BUG this << " on exit root : ";
	it_r.dumpDbg2();
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
ETI_CplxTxt * 		ETI_CplxTxt::loadXML			(
		ETSheet * dest, QDomElement dom_e)
{
	QDomElement dom_it;
	QDomElement dom_sit;
	ETI_CplxTxt * ret_it = new ETI_CplxTxt() ;

	/* common properties for all items inheriting from */
	dom_it = dom_e.firstChildElement(XML_TAG_COMM);
	if (!dom_it.isNull())
	{
		ETSheet::loadQICommon(ret_it, dom_it);

		if (!dom_it.nextSiblingElement(XML_TAG_COMM).isNull())
		{
			qDebug() << "The input presented more than one "
					 << "common tags, when only one per ETI_CplxTxt element "
					 << "is allowed";
		}
	}

	/* the one and only sub-items that has to be of root type */
	dom_it = dom_e.firstChildElement(XML_TAG_SUBITEM);
	if (!dom_it.isNull())
	{
		dom_sit = dom_it.firstChildElement(XML_TAG_TYPE);
		if (!dom_sit.isNull())
		{ /* silently ignore the lack of type and assume root */

			if (dom_sit.text() != XML_SIT_ROOT)
			{

				qDebug() << "The input presented an sub-item that "
						 << "was not of root type. Top level "
						 << "sub-item in a ETI_CplxTxt needs to be "
						 << "of root type. Period.";
				delete ret_it;
				return NULL;

			}
		}
		/* this call will load entire chain of sub-items */
		ETSI_Root::loadXML(dom_it, &ret_it->it_r);

		if (!dom_it.nextSiblingElement(XML_TAG_SUBITEM).isNull())
		{
			qDebug() << "The input presented more than one "
					 << "top level sub-items, when only one per ETI_CplxTxt element "
					 << "is allowed";
		}
	}

	/* get the bounding boxes for all items */
	ret_it->recompute(true);

	/* and insert it in the sheet */
	dest->addItem(ret_it);

	return ret_it;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void 		ETI_CplxTxt::saveXML			(
		QDomElement dom_e)
{

	/* save common data */
	QDomElement dom_it = dom_e.ownerDocument().createElement(XML_TAG_COMM);
	dom_e.appendChild(dom_it);
	ETSheet::saveQICommon(this, dom_it);

	/* the root item (will tigger a full save) */
	dom_it = dom_e.ownerDocument().createElement(XML_TAG_SUBITEM);
	dom_e.appendChild(dom_it);
	it_r.saveXML(dom_it);

}
/* ========================================================================== */

/* ------------------------------------------------------------------------- */
ETI_CplxTxt *	ETI_CplxTxt::createHost	(
		ETSheet * dest, QPointF pos, ETSubItem::SIType sit_ty )
{

	ETI_CplxTxt * ret_it = new ETI_CplxTxt();
	ETSubItem * new_si = NULL;

	/// @todo add code to create sub-item types as they get defined

	switch	(sit_ty)		{
	case	ETSubItem::TYFRACT:		{
		ETSI_Fract * only_it = new ETSI_Fract();
		new_si = static_cast<ETSubItem *>(only_it);
		break; }
		//	case	ETSubItem::TYHTEXT:		{
		//		ETSI_HText * only_it = new ETSI_HText();
		//		new_si = static_cast<ETSubItem *>(only_it);
		//		break; }
		//	case	ETSubItem::TYINTEG:		{
		//		ETSI_Integ * only_it = new ETSI_Integ();
		//		new_si = static_cast<ETSubItem *>(only_it);
		//		break; }
		//	case	ETSubItem::TYLIM:		{
		//		ETSI_Lim * only_it = new ETSI_Lim();
		//		new_si = static_cast<ETSubItem *>(only_it);
		//		break; }
		//	case	ETSubItem::TYLOGICAC:	{
		//		ETSI_LogicAc * only_it = new ETSI_LogicAc();
		//		new_si = static_cast<ETSubItem *>(only_it);
		//		break; }
		//	case	ETSubItem::TYMATRIX:	{
		//		ETSI_Matrix * only_it = new ETSI_Matrix();
		//		new_si = static_cast<ETSubItem *>(only_it);
		//		break; }
		//	case	ETSubItem::TYRADIC:		{
		//		ETSI_Radic * only_it = new ETSI_Radic();
		//		new_si = static_cast<ETSubItem *>(only_it);
		//		break; }
		//	case	ETSubItem::TYSUM:		{
		//		ETSI_Sum * only_it = new ETSI_Sum();
		//		new_si = static_cast<ETSubItem *>(only_it);
		//		break; }
	default:/* TYROOT TYSTEXT TYMAX errors */	{
		ETSI_SText * only_it = new ETSI_SText();
		new_si = static_cast<ETSubItem *>(only_it);
		break; }
	}


	/* append this newly created sub-item to the chain */
	ret_it->it_r.append(new_si);


	/* get the bounding boxes for item */
	ret_it->recompute(true);

	/* and insert it in the sheet */
	dest->addItem(ret_it);
	ret_it->setPos(pos);

	return ret_it;
}
/* ========================================================================= */



/*  CLASS    =============================================================== */
//
//
//
//
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
